home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / ovrobj.com / OVROBJ.DOC < prev   
Encoding:
Text File  |  1989-11-29  |  8.4 KB  |  163 lines

  1.                                   OVROBJ
  2.                                 Version 1.0
  3.                                 Ron Schuster
  4.  
  5. Overview
  6. -----------------------------------------------------------------------------
  7. The Turbo Pascal User's Guide shows how to use the BINOBJ utility to link data
  8. directly into your program by first converting the data into an OBJ file.  Such
  9. "OBJitized" data normally cannot be used in an overlaid unit.  This file
  10. explains the reason for this restriction and provides a convenient method to
  11. circumvent it.  
  12.  
  13.  
  14. Using OvrObj
  15. -----------------------------------------------------------------------------
  16. OvrObj is a small inline macro that returns a pointer to the OBJitized data,
  17. whether or not the unit is overlaid.  To use it, add the OVR_OBJ unit to the
  18. uses statement in the unit being overlaid.  Then you can access the OBJitized
  19. data as follows:
  20.  
  21.   PtrVar := OvrObj (@ProcName);
  22.  
  23. ProcName is the procedure name assigned to the OBJitized data.  PtrVar is a
  24. pointer variable of any appropriate type.  Alternatively, the pointer returned
  25. by OvrObj can be dereferenced directly with suitable typecasting.  See
  26. DEMOUNIT.PAS for examples of both approaches.
  27.  
  28.  
  29. Restrictions 
  30. ---------------------------------------------------------------------------- 
  31. 1)  OvrObj must be used in the same unit as the data itself.  This ensures
  32. that the data is actually loaded into memory when you access it.
  33.  
  34. 2)  If you assign the value returned by OvrObj to a pointer variable, rather
  35. than deferencing it directly, its value is only guaranteed to be valid until
  36. the next time a new unit gets loaded into the overlay buffer.  Keep in mind
  37. that the pointer returned by OvrObj is an address within the overlay buffer. 
  38. Any time the overlay manager gets control, it can, and frequently does, move
  39. any or all units within the overlay buffer to different memory locations.  Any
  40. such action will invalidate any OvrObj pointers you have stored in variables.
  41. This can happen when the current procedure ends, or when a call is made to a
  42. procedure in another overlaid unit, either directly or indirectly.  
  43.  
  44.  
  45. Running the demo
  46. -----------------------------------------------------------------------------
  47. Using the BINOBJ program supplied with your copy of Turbo Pascal, convert the
  48. text file DEMOTEXT.TXT to an OBJ file:
  49.  
  50.   BINOBJ DEMOTEXT.TXT DEMOTEXT.OBJ DEMOTEXT
  51.  
  52. Then compile DEMO and DEMOUNIT normally.  When you run DEMO, the string
  53. contained in DEMOTEXT.TXT is displayed on the screen twice.
  54.  
  55.  
  56. Why is OvrObj needed?
  57. -----------------------------------------------------------------------------
  58. Borland's documentation suggests that the OBJ files produced by BINOBJ
  59. shouldn't be used in an overlaid unit.  But the problem isn't really that the
  60. data shouldn't be overlaid.  It's just that getting the address of that data is
  61. much less straightforward when it is overlaid.
  62.  
  63. First, we'll need a little background about how the overlay system works.  
  64. For the purposes of this discussion, each overlaid unit has two parts: a static
  65. "dispatcher" segment, and the actual overlaid code.  Each static dispatcher is
  66. a small code segment that's linked into the EXE file.  A unique dispatcher
  67. always remains in memory for each overlaid unit.  Whenever you call a procedure
  68. in an overlaid unit, you're really calling a tiny (5 byte) routine in the
  69. static dispatcher.  If the overlay is already loaded into memory, the 5 byte
  70. "routine" is just a far jump instruction that immediately transfers control to
  71. the real code in the overlay buffer.  If the overlay isn't currently loaded,
  72. the 5 bytes specify an INT $3F instruction and one word of data.  The INT $3F
  73. serves to transfer control to the OVERLAY unit, which finds space for the
  74. overlay (perhaps by booting out other overlays), loads the actual overlay code
  75. into memory from the OVR file, patches direct jump instructions into the static
  76. dispatcher, and jumps to the requested procedure.  The data word specifies the
  77. code offset of the routine being called and is used to create the jump
  78. instruction.
  79.  
  80. So how does all this relate to OBJitized data?  Borrowing from the example on
  81. page 288 in the Turbo Pascal User's Guide:
  82.  
  83.         procedure MenuData; external;
  84.         {$L MENUDTA.OBJ}
  85.         ...
  86.           ShowScreen(@MenuData);
  87.         ...
  88.  
  89. In the example in the book, @MenuData will always be equal to the address of
  90. the actual data since it is defined in the main program.  This is also the case
  91. if you define MenuData in a non-overlaid unit.  However, if you overlay that
  92. unit, the value of @MenuData will be the address of MenuData's 5 byte entry in
  93. the static dispatcher.  Since this is probably not the address you wanted,
  94. Borland simply recommends that you not do this, but we will use that address
  95. later to find out where the data really is.
  96.  
  97. Note that this depends on whether or not the unit is actually overlaid (i.e.,
  98. does the {$O UnitName} directive appear in the main program?), and not just
  99. whether unit was compiled with the $O+ directive.
  100.  
  101.  
  102. Finding the data
  103. -----------------------------------------------------------------------------
  104. In the example above, if the unit is overlaid, and the unit has been loaded,
  105. then @MenuData is the address of the far jump instruction to the actual data.
  106. Although we don't intend to jump to our data, we can get its address from the
  107. 5-byte jump instruction.  The first byte is the far jump op-code.  The
  108. remaining 4 bytes give us the complete segment and offset address of the actual
  109. data in the overlay buffer.
  110.  
  111. Therefore, in order to decide how to handle itself, a unit must first determine
  112. whether it really has been overlaid.  This can be done by looking a offset 0 of
  113. the unit's segment.  If the unit is overlaid this will contain the static
  114. dispatcher, which always begins with an INT $3F instruction, regardless of
  115. whether or not the unit is loaded.  If you consider that to be a Word, the
  116. number $3FCD is stored there.
  117.  
  118. Note that this is not fool-proof.  It is possible that a non-overlaid unit may
  119. have that special number at that particular location.  This would occur in the
  120. unlikely case that the program had range-checking turned on, and the first
  121. range declared in the unit had a lower bound having $3FCD as its least
  122. significant 16-bits.  This would seem highly unlikely unless a malicious
  123. attempt is made by the programmer to confuse the "overlay detector".  Although
  124. a more robust check could be written using other known information about the
  125. static dispatcher format, this would probably be more compiler-version
  126. dependent, and would certainly be slower.  Given its simplicity and extremely
  127. low probability of failure, the one-word comparison seems the better choice.  
  128.  
  129.  
  130. Putting it all together
  131. -----------------------------------------------------------------------------
  132. Now we can see how OvrObj works.  First, it checks the word at offset 0 of the
  133. unit.  If it is equal to $3FCD, indicating that the unit is overlaid, then X is
  134. the address of the far jump instruction in the static dispatcher.  Incrementing
  135. the offset of X by 1 gets us to the address portion of the jump instruction,
  136. which is the real address of the data.  This address is returned to the caller.
  137.  
  138. If the word at offset 0 is not equal to $3FCD, then the unit is not overlaid
  139. and the value of X is returned unchanged, since it is the actual address of the
  140. data. 
  141.  
  142.  
  143. End.
  144. -----------------------------------------------------------------------------
  145. OvrObj was written by Ron Schuster.  It is copyright (c)1989 by Ron Schuster.
  146. It may be distributed freely, but not for a profit.
  147.  
  148. If you have problems, suggestions, or enhancements, please contact me on
  149. CompuServe [76666,2322].
  150.  
  151. I first became aware of this technique through the file OBJOVR.ARC by David
  152. Dubois.  Anyone who has implemented the technique as presented in this file
  153. should be aware that it contains an error that can produce an intermittent
  154. bug.  The problem is in the "overlay detector".  It does a two-word (LongInt)
  155. comparison that assumes that the second word is always zero, which is not
  156. always true.
  157.  
  158. Portions of this documentation were adapted from OBJOVR.ARC by David Dubois
  159. [71401,747] and OVRSIZ.ARC by Kim Kokkonen [76004,2611] with permission from
  160. the authors.  For a more detailed explanation of the internal workings of the
  161. overlay system, download the file OVRLAY.TXT.  These files are all available
  162. on CompuServe (BPROGA forum LIB 2).
  163.